package com.qunar.wan.service;

import com.google.common.base.Preconditions;
import com.qunar.wan.common_api.model.Query;
import com.qunar.wan.common_api.model.Sort;
import com.qunar.wan.common_api.model.User;
import com.qunar.wan.common_api.model.enums.Role;
import com.qunar.wan.common_api.service.AdminLogService;
import com.qunar.wan.common_api.service.UserService;
import com.qunar.wan.common_api.service.mapper.UserMapper;
import com.qunar.wan.tools.AppConfig;
import com.qunar.wan.common_api.serializer.RowBounds;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.List;

/**
 * User: tongjie.yang Date: 11/25/13 Time: 6:47 PM
 */
@Service("userService")
public class  UserServiceImpl extends BaseServiceImpl<User, UserMapper> implements UserService {

    private final static String DEFAULT_EMAIL_SUFFIX = AppConfig.getItem("user.email.suffix", "@qunar.com"); // 默认邮箱前缀

    private final static int DEFAULT_USER_TOTALSCORE = AppConfig.getIntItem("user.totalscore.init", "10"); // 用户默认分数

    @Value("#{settings['cookie.maxAge']}")
    private int COOKIE_MAX_AGE=3600;
    @Value("#{settings['cookie.key']}")
    private String  COOKIE_KEY="xxxxx";
    private final static String COOKIE_NAME = "QNRWAN";
    @Resource
    private AdminLogService adminLogService;

    /**
     * @return List<user>
     */
    @Override
    public List<User> selectStarUser(int num) {
        Preconditions.checkArgument(num > 0, "num must more than 0");
        List<User> starUsers = selectByQuery(new Query().addSort(new Sort("total_score", Sort.Order.DESC)),
                new RowBounds(0, num));
        return starUsers;
    }

    /**
     * @param role
     * @return List<user>
     */
    @Override
    public List<User> selectUserByRole(Role role) {
        List<User> users = selectByQuery(new Query("role", role));
        return users;
    }

    /**
     * @param userName
     * @return User
     */
    @Override
    public User selectUserByName(String userName) {
        Preconditions.checkNotNull(userName);
        List<User> users = selectByQuery(new Query("userName", userName));
        return users.isEmpty() ? null : users.get(0);
    }

    /**
     * @param userId
     * @return User
     */
    @Override
    public User selectUserById(int userId) {
        Preconditions.checkArgument(userId > 0, "userId must greater than 0,your input:" + userId);
        List<User> users = selectByQuery(new Query("id", userId));
        return users.isEmpty() ? null : users.get(0);
    }

    /**
     * @param userName
     * @return User
     */
    @Override
    public User loginHandler(String userName) {
        Preconditions.checkNotNull(userName);
        // 判断用户之前是否登录过
        User user = selectUserByName(userName);
        if (user != null) {
            updateUserLoginTime(user.getId(), new Date());
            if (user.getRole() == Role.MANAGER) {
                adminLogService.insertAdminLog(user.getId(), "登录系统");
            }
            return user;
        }
        // 如果没有登录过，将用户的完整信息插入数据库
        user = new User();
        user.setUserName(userName);
        user.setEmail(userName + DEFAULT_EMAIL_SUFFIX);
        user.setRole(Role.USER);
        user.setTotalScore(DEFAULT_USER_TOTALSCORE);
        user.setHeadImg("defaulthead.jpg");
        user.setIsFirstLogon(true);
        insertObj(user);
        return user;
    }

    /**
     * @param userId
     * @param score
     */
    @Override
    public void addUserScore(int userId, int score) {
        User user = selectUserById(userId);
        user.setTotalScore(user.getTotalScore() + score);
        updateObj(user);
    }

    /**
     * @param userId
     * @param role
     */
    @Override
    public void updateUserRole(int userId, Role role) {
        Preconditions.checkNotNull(role);
        User user = selectUserById(userId);
        user.setRole(role);
        updateObj(user);
    }

    /**
     * @param userId
     * @param headUrl
     */
    @Override
    public void updateUserHeadImg(int userId, String headUrl) {
        Preconditions.checkNotNull(headUrl);
        User user = selectUserById(userId);
        user.setHeadImg(headUrl);
        updateObj(user);
    }

    /**
     * @param userId
     * @param date
     */
    @Override
    public void updateUserLoginTime(int userId, Date date) {
        Preconditions.checkNotNull(date);
        User user = selectUserById(userId);
        user.setLoginTime(date);
        updateObj(user);
    }

    /**
     * 获取所有用户，分页显示
     *
     * @param rowBounds
     * @return
     */
    @Override
    public List<User> selectAllUser(RowBounds rowBounds) {
        return selectByQuery(new Query(), rowBounds);
    }

    /**
     * 查询用户总数
     *
     * @return
     */
    @Override
    public int selectUserNum() {
        return selectAllUser(new RowBounds()).size();
    }


    @Override
    public void writeUserCookie(User user) {
        logger.info("写入cookie：{}", user);
        long validTime = System.currentTimeMillis() + (COOKIE_MAX_AGE * 1000);
        HttpServletResponse response = ((ServletWebRequest) RequestContextHolder.getRequestAttributes()).getResponse();
        String md5OrigValue = new StringBuilder(String.valueOf(user.getId())).append(user.getUserName())
                .append(user.getIsFirstLogon()).append(COOKIE_KEY).toString();
        String cookieValueWithMd5 = DigestUtils.md5Hex(md5OrigValue);
        String cookieValue = new StringBuilder(String.valueOf(user.getId())).append(";").append(user.getUserName())
                .append(";").append(user.getIsFirstLogon()).append(";").append(validTime).append(";")
                .append(cookieValueWithMd5).toString();
        String cookieValueBase64 = new String(Base64.encodeBase64URLSafeString(cookieValue.getBytes()));
        StringBuilder cookie = new StringBuilder(COOKIE_NAME).append("=").append(cookieValueBase64)
                .append(";Path=/; Max-Age=").append(COOKIE_MAX_AGE).append(";HttpOnly");
        response.addHeader("Set-Cookie", cookie.toString());
    }

    @Override
    public String getIsFirst() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String[] userCookieValue = getUserCookies(request);
        return userCookieValue != null && userCookieValue.length == 5 ? userCookieValue[2] : null;
    }

    @Override
    public User identifyUser(String usernameOremail, String password) {
        List<User> users = selectByQuery(new Query("username",usernameOremail));
        users =  users.size()>0?users:selectByQuery(new Query("password",password));
        return users.size()>0?users.get(0):null;
    }

    @Override
    public User currentLogonUser() {
        if(null == RequestContextHolder.getRequestAttributes()){
            return null;
        }
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String[] userCookieValue = getUserCookies(request);
        String userId =  userCookieValue != null && userCookieValue.length == 5 ? userCookieValue[0] : null;
        return userId == null?null:selectUserById(Integer.parseInt(userId));
    }

    @Override
    public void emptyUserCookie() {
        Cookie namecookie = new Cookie(COOKIE_NAME, "");
        namecookie.setMaxAge(0);
        namecookie.setPath("/");
        HttpServletResponse response = ((ServletWebRequest) RequestContextHolder.getRequestAttributes()).getResponse();
        response.addCookie(namecookie);
    }


    private String[] getUserCookies(HttpServletRequest request) {
        Cookie cookies[] = request.getCookies();
        if (null == cookies || cookies.length == 0) {
            return null;
        }
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(COOKIE_NAME)) {
                String cookieValue = cookie.getValue();
                String decodeBase64 = "";
                try {
                    cookieValue = URLDecoder.decode(cookieValue, "UTF-8");
                    decodeBase64 = new String(Base64.decodeBase64(cookieValue), "utf-8");
                } catch (UnsupportedEncodingException e) {
                    logger.error("", e);
                }
                // 长度匹配
                String cookieValues[] = decodeBase64.split(";");
                if (cookieValues.length != 5) {
                    logger.warn("用户可能非法登录，cookie值为{}", decodeBase64);
                    return null;
                }
                // 验证MD5值
                String md5OriValue = new StringBuilder(cookieValues[0]).append(cookieValues[1]).append(cookieValues[2])
                        .append(COOKIE_KEY).toString();
                if (!DigestUtils.md5Hex(md5OriValue).equals(cookieValues[4])) {
                    logger.warn("用户Cookie MD5不一致，cookie值为{}",  decodeBase64);
                    return null;
                }
                // 验证有效期
                Date validTime = new Date(Long.parseLong(cookieValues[3]));
                if (validTime.before(new Date())) {
                    logger.warn("用户Cookie过期，cookie值为{}",  decodeBase64);
                    return null;
                }
                return cookieValues;
            }
        }
        return null;

    }

}
